#include <hld/nim/nim_dev.h>
#include <hld/decv/decv.h>
#include <hld/deca/deca_dev.h>
#include <hld/snd/snd_dev.h>
#include <hld/dmx/dmx_dev.h>
#include <hld/dmx/dmx.h>
#include <api/libtsi/db_3l.h>
#include <api/libc/string.h>
#include <bus/tsi/tsi.h>
#include <api/libdiseqc/lib_diseqc.h>
#include <api/libsi/si_tdt.h>
#include <api/libpub/lib_frontend.h>
#include <api/libpub/lib_as.h>
#include <api/libpub/lib_device_manage.h>
#include <api/libci/ci_plus.h>

/*******************************************************
* macro define
********************************************************/
#define CC_MAX_TS_ROUTE_NUM 5


/*******************************************************
* extern declare
********************************************************/
UINT16 l_cc_sema_id = OSAL_INVALID_ID;
#define ENTER_FRONTEND_API()	do	\
								{	\
									if (l_cc_sema_id != OSAL_INVALID_ID)	\
										osal_semaphore_capture(l_cc_sema_id, TMO_FEVR);	\
								}while(0)
#define LEAVE_FRONTEND_API()	do	\
								{	\
									if (l_cc_sema_id != OSAL_INVALID_ID)	\
										osal_semaphore_release(l_cc_sema_id);	\
								}while(0)
								

/*******************************************************
* struct and variable
********************************************************/
static double local_longtitude;
static double local_latitude;

//extern struct dmx_device *g_dmx_dev, *g_dmx_dev2, *g_dmx_dev3;
INT8 nim_tsiid[3] = {TSI_SPI_0, TSI_SPI_1, TSI_SPI_TSG};
static struct ts_route_info g_ts_route_info[CC_MAX_TS_ROUTE_NUM];
typedef void (*v12set_callback)(UINT32 v12);
static v12set_callback l_v12set_callback = NULL;
/********************************************************
*internal functions
/*******************************************************/
void UIChChgSet12VSetCB(v12set_callback v12setcb)
{
	l_v12set_callback = v12setcb;
}

// copy from "ci_is_av_scrambled" as a common API
BOOL ts_route_is_av_scrambled(struct dmx_device *dmx, UINT16 v_pid, UINT16 a_pid)
{
	BOOL ret = FALSE;
	RET_CODE dmx_state = RET_FAILURE;
	struct io_param param;
	struct io_param_ex param_ex;
	UINT16 PID[2];
	UINT8 scramble_type=0;
		
	if (dmx != NULL)
	{
		PID[0] = v_pid;
		PID[1] = a_pid;
		if (ALI_M3329E == sys_ic_get_chip_id())
		{
			MEMSET(&param, 0, sizeof(param));
			param.io_buff_in = (UINT8 *)PID;
			param.io_buff_out= (UINT8 *)&scramble_type;
			dmx_state = dmx_io_control(dmx, IS_AV_SCRAMBLED_EXT, (UINT32)&param);			
		}
		else if(ALI_S3602F == sys_ic_get_chip_id() || ALI_S3281 == sys_ic_get_chip_id())
		{
			MEMSET(&param_ex, 0, sizeof(param_ex));
			param_ex.io_buff_in = (UINT8 *)PID;
			param_ex.io_buff_out= (UINT8 *)&scramble_type;
			dmx_state = dmx_io_control(dmx, IS_AV_SCRAMBLED_EXT, (UINT32)&param_ex);			
		}
		else
		{
			//for 3602 do not support IS_AV_SCRAMBLED_EXT
			dmx_state = dmx_io_control(dmx, IS_AV_SCRAMBLED, (UINT32)&scramble_type);
		}
		
		//fix issue: for AC3 audio is AUD_STR_INVALID
//		if((dmx_state == SUCCESS ) && ((scramble_type & (VDE_TS_SCRBL|VDE_PES_SCRBL|AUD_TS_SCRBL|AUD_PES_SCRBL|VDE_STR_INVALID|AUD_STR_INVALID)) != 0))
		if((dmx_state == SUCCESS ) && ((scramble_type & (VDE_TS_SCRBL|VDE_PES_SCRBL|AUD_TS_SCRBL|AUD_PES_SCRBL)) != 0))
		{
			ret = TRUE;
		}
	}

	return ret;
}

/* Get Number of Valid TS Route */
static UINT8 __ts_route_get_valid(void)
{
	UINT16 i;

	for(i = 0; i < CC_MAX_TS_ROUTE_NUM; i++)
	{
		if(g_ts_route_info[i].enable == 0)
		{
			break;
		}
	}

	return i;
}

/* Get Lock Flag and Scramble Flag of TS Route */
static void __ts_route_check_flag(struct ts_route_info *ts_route)
{
	struct dmx_device *dmx = NULL;
	struct nim_device *nim = NULL;
	UINT32 scrabled, scrable_typ;
	P_NODE node;

	//may have problem!
	
	if((ts_route->state & TS_ROUTE_STATUS_PLAYACK) == 0)
	{
		dmx = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, ts_route->dmx_id);
		nim = (struct nim_device *)dev_get_by_id(HLD_DEV_TYPE_NIM, ts_route->nim_id);

		//Check whether NIM Signal is Locked or not
		nim_get_lock(nim, &ts_route->flag_lock);

#if 0 //def CI_PLUS_SUPPORT
		ts_route->flag_scramble = 0;

		//Check whether TS Stream in DMX is Scrambled or not and Scamble Type
		if(get_prog_by_id(ts_route->prog_id, &node) != SUCCESS)
		{
			return;
		}
		
		ts_route->flag_scramble = ts_route_is_av_scrambled(dmx, node.video_pid, node.audio_pid[node.cur_audio]);
#else
		//Check whether TS Stream in DMX is Scrambled or not and Scamble Type
		scrabled = 0;
		if(dmx_io_control(dmx, IS_AV_SCRAMBLED, (UINT32)(&scrable_typ)) == RET_SUCCESS)
		{
			ts_route->flag_scramble = (scrable_typ & (VDE_TS_SCRBL|VDE_PES_SCRBL));
		}
#endif
	}

	return;
}


/*******************************************************
* external APIs
********************************************************/
//set Unicable
void frontend_set_unicable(struct nim_device *nim,struct ft_antenna* antenna,union ft_xpond* xpond)
{
    UINT8 Band;
    UINT16 Flo;

	if (antenna->lnb_type == LNB_CTRL_UNICABLE /* UNICABLE LNB */)
	{
        if (xpond->s_info.frq > KU_LNB_22K_EDGE_FREQUENCY/*11700*/)
        {
            Band = 1;
            Flo = antenna->lnb_high;
        }
        else
        {
            Band = 0;
            Flo = antenna->lnb_low;
        }
		api_diseqc_unicable_channel_change(nim,
							antenna->unicable_ub,/*UB*/
							antenna->unicable_freq,/*Fub*/
							antenna->unicable_pos,/*Position A(0)/B(1)*/
							1-xpond->s_info.pol,/*Polarization*/
							Band,/*High band or Low band*/
							xpond->s_info.frq-Flo/*Fif*/);        
//    osal_task_sleep(50);
    }
}

/* Set NIM Info */
void frontend_set_nim(struct nim_device *nim, struct ft_antenna* antenna, 
    union ft_xpond* xpond, UINT8 force_set)
{
    	struct NIM_Channel_Change nim_param;
    	INT32 tuning_frq = 0;
    	struct nim_config config;

	//Get Old NIM Config Info
    	dev_get_nim_config(nim, xpond->common.type, &config);
    
    	MEMSET(&nim_param, 0, sizeof(nim_param));

	/* DVB-S Frontend, Antenna Config is Valid*/
	/* Tuning DVB-S NIM */
    	//if((antenna != NULL) && (antenna->antenna_enable == 1))
    	//change on 2012-02-14 for no signal after auto scan (set win_miscset_save_setting -> antenna->antenna_enable = 0)  
    	if(xpond->common.type == FRONTEND_TYPE_S && (antenna != NULL))
    	{

        	struct t_diseqc_info d_info;
        	UINT8 pol;            
        	pol = antenna->pol==0? (xpond->s_info.pol+1):antenna->pol;

        	//if((!l_cc_local_ismutex)||(pAntenna->positioner_type == 0))
        	{
        		d_info.sat_or_tp = 1;
        		d_info.diseqc_type = antenna->DiSEqC_type;
        		d_info.diseqc_port = antenna->DiSEqC_port;
        		d_info.diseqc11_type = antenna->DiSEqC11_type;
        		d_info.diseqc11_port = antenna->DiSEqC11_port;
        		if(antenna->lnb_type==LNB_CTRL_22K)
        		{
        		 	if(xpond->s_info.frq >= KU_LNB_22K_EDGE_FREQUENCY)
        				d_info.diseqc_k22 = 1;
        			else
        				d_info.diseqc_k22 = 0;
        		}
        		else
        		d_info.diseqc_k22 = antenna->k22;

        		d_info.diseqc_polar = pol;
        		d_info.diseqc_toneburst = antenna->toneburst;	/* 0: off, 1: A, 2: B */
        		api_diseqc_operation(nim, &d_info, force_set);
        	}
        
        	switch(antenna->lnb_type)
        	{
            	case LNB_CTRL_22K:
                	if(xpond->s_info.frq > KU_LNB_22K_EDGE_FREQUENCY)
                	{
                    		api_diseqc_set_22k(nim, 1);
                    		tuning_frq = xpond->s_info.frq - ((antenna->lnb_high > antenna->lnb_low) ? antenna->lnb_high : antenna->lnb_low);
                	}
                	else
                	{
                    		api_diseqc_set_22k(nim, 0);
                    		tuning_frq = xpond->s_info.frq - ((antenna->lnb_high > antenna->lnb_low) ? antenna->lnb_low : antenna->lnb_high);
                	}
              	break;
            	case LNB_CTRL_POL:
                	pol = ((antenna->pol == 0) || (antenna->pol == 3)) ? (xpond->s_info.pol + 1) : (antenna->pol);
                	if(pol == 1)
                	{
                    		tuning_frq = antenna->lnb_low - xpond->s_info.frq;
                	}
                	else
                	{
                    		tuning_frq = antenna->lnb_high - xpond->s_info.frq;
                	}
                	break;
                case LNB_CTRL_UNICABLE:  
//                    frontend_set_unicable(nim,antenna,xpond);
                    tuning_frq = antenna->unicable_freq;                    
                    break;
            	case LNB_CTRL_STD:
            	default:
                    tuning_frq = (((antenna->lnb_low != 0) ? antenna->lnb_low : antenna->lnb_high)) - xpond->s_info.frq;
                	break;
        	}
			
        	if(tuning_frq < 0)
        	{
            		tuning_frq = -tuning_frq;
        	}
			
        	nim_param.sym = xpond->s_info.sym;
    	}
    	else
    	{
        	/* Tuning DVB-C NIM */
        	if(xpond->common.type == FRONTEND_TYPE_C)
        	{
            		tuning_frq = xpond->c_info.frq;
            		nim_param.sym = xpond->c_info.sym;
            		nim_param.modulation = xpond->c_info.modulation;
        	}
        	/* Tuning DVB-T NIM */
        	else if(xpond->common.type == FRONTEND_TYPE_T)
        	{
            		tuning_frq = xpond->t_info.frq;
            		nim_param.sym = xpond->t_info.sym;
            		nim_param.fec = xpond->t_info.fec;
            		nim_param.guard_interval = xpond->t_info.guard_intl;
            		nim_param.fft_mode = xpond->t_info.fft_mode;
            		nim_param.modulation = xpond->t_info.modulation;
            		nim_param.usage_type = xpond->t_info.usage_type;
            		nim_param.inverse = xpond->t_info.inverse;
                    nim_param.bandwidth = xpond->t_info.band_width/1000;

                    //(DVBT2_SUPPORT)
                    nim_param.t2_signal = xpond->t_info.t2_signal;
                    nim_param.plp_index = xpond->t_info.plp_index;
                    nim_param.plp_id = xpond->t_info.plp_id;    //For play program according to the plp_id, and regardless which plp_index it's broadcasted with.
                    nim_param.plp_num = xpond->t_info.plp_num;  //Keep plp_num for support USAGE_TYPE_NEXT_PIPE_SCAN.
                    nim_param.t2_profile = xpond->t_info.t2_profile;
				if(nim_param.usage_type == (UINT8)USAGE_TYPE_CHANCHG)//play channle     
				{                      
				   	nim_param.priority = xpond->t_info.priority;
				}
                    else //scan
                    {
                        nim_param.priority = 0;
                    }
        	}
    	}
    	nim_param.freq = tuning_frq;


#if 0
	/* Set NIM Using the Tuning Param */
	if(xpond->common.type == FRONTEND_TYPE_T)
	{
		/* for tp node not save priority
		if(nim_param.usage_type==0x2)//play channle
		{
			nim_channel_change(nim, tuning_frq, nim_param.bandwidth, nim_param.guard_interval, nim_param.fft_mode,
				nim_param.modulation, nim_param.fec, nim_param.usage_type, nim_param.inverse, xpond->t_info.priority);
		}
		else//scan
		*/
		{
			nim_channel_change(nim, tuning_frq, nim_param.bandwidth/1000, nim_param.guard_interval, nim_param.fft_mode,
				nim_param.modulation, nim_param.fec, nim_param.usage_type, nim_param.inverse, 0);
/*
			if( api_nim_HIER_mode() )//not low priority
				nim_channel_change(nim, tuning_frq, nim_param.bandwidth, nim_param.guard_interval, nim_param.fft_mode,
					nim_param.modulation, nim_param.fec, nim_param.usage_type, nim_param.inverse, 2);
*/					
		}
	}
	else
	{
    	if(nim->do_ioctl_ext)
    	{
        	nim->do_ioctl_ext(nim, NIM_DRIVER_CHANNEL_CHANGE, (void *)(&nim_param));
    	}
	}
 #endif
 
     if(nim->do_ioctl_ext)
     {
         nim->do_ioctl_ext(nim, NIM_DRIVER_CHANNEL_CHANGE, (void *)(&nim_param));
     }

#if defined(DVBT2_SUPPORT)
    xpond->t_info.t2_signal = nim_param.t2_signal;
    xpond->t_info.plp_index = nim_param.plp_index;
    xpond->t_info.plp_id = nim_param.plp_id;
    xpond->t_info.t2_system_id = nim_param.t2_system_id;
    xpond->t_info.plp_num = nim_param.plp_num;
    xpond->t_info.t2_profile = nim_param.t2_profile;
#endif
        
 
	//Store New NIM Config Info
    	MEMCPY(&config.xpond, xpond, sizeof(union ft_xpond));
    	dev_set_nim_config(nim, xpond->common.type, &config);
}


/* Set Antenna Info */
void frontend_set_antenna(struct nim_device *nim, struct ft_antenna* antenna, 
    union ft_xpond* xpond, UINT8 force_set)
{
    	//if((antenna != NULL) && (antenna->antenna_enable == 1))
    	//change on 2012-02-13 for dvbs not set this param (set win_miscset_save_setting -> antenna->antenna_enable=0)  
    	if(xpond->common.type == FRONTEND_TYPE_S && (antenna != NULL))
    	{
        	struct t_diseqc_info d_info;
        	UINT8 tp_pol;
        	struct nim_config config;
            
		if(l_v12set_callback != NULL)
			l_v12set_callback(antenna->v12);
        
		//Get Old NIM Config
        	if(SUCCESS != dev_get_nim_config(nim, FRONTEND_TYPE, &config))
        	{
            		return;
        	}

		//Store New NIM Config
        	MEMCPY(&config.antenna, antenna, sizeof(struct ft_antenna));
        	dev_set_nim_config(nim, FRONTEND_TYPE, &config);

		//Set Diseqc Info and Operate
        	tp_pol = xpond->s_info.pol + 1;
        	MEMSET(&d_info, 0, sizeof(d_info));
        	d_info.sat_or_tp = 0;
        	d_info.diseqc_type = antenna->DiSEqC_type;
        	d_info.diseqc_port = antenna->DiSEqC_port;
        	d_info.diseqc11_type = antenna->DiSEqC11_type;
        	d_info.diseqc11_port = antenna->DiSEqC11_port;
        	d_info.diseqc_toneburst = antenna->toneburst;
        	d_info.diseqc_polar = (antenna->pol == 0) ? (tp_pol) : (antenna->pol);
            if(antenna->lnb_type==LNB_CTRL_22K)
            {
                if(xpond->s_info.frq >= KU_LNB_22K_EDGE_FREQUENCY)
                    d_info.diseqc_k22 = 1;
                else
                    d_info.diseqc_k22 = 0;
            }
            else
                d_info.diseqc_k22 = antenna->k22;   

        	/* Set Positioner Type Motor */
        	d_info.positioner_type = antenna->positioner_type;
        	/* Diseqc1.2 Motor */
        	if(antenna->positioner_type == 1)
        	{
            		d_info.position = antenna->position;
        	}
        	/* Usal Motor */
        	else if(antenna->positioner_type == 2)
        	{
            		double sat_obit = api_usals_get_sat_orbit(antenna->longitude);
            		double longtitude = 0;
            		double latitude = 0;

            		chchg_get_local_position(&longtitude, &latitude);
            		d_info.wxyz = api_usals_xx_to_wxyz(api_usals_target_formula_calcuate(sat_obit, longtitude, latitude));
        	}
        	else
        	{
            		d_info.positioner_type = 0;
        	}
		//Operate Diseqc	
        	api_diseqc_operation(nim, &d_info, force_set);   
        //set Unicable LNB if exist
        	if (antenna->lnb_type == LNB_CTRL_UNICABLE)
                frontend_set_unicable(nim,antenna,xpond);  
    	}
}

/* Set Antenna and NIM Info */
void frontend_tuning(struct nim_device *nim, struct ft_antenna* antenna, 
    union ft_xpond* xpond, UINT8 force_set)
{
    	frontend_set_antenna(nim, antenna, xpond, force_set);
    	frontend_set_nim(nim, antenna, xpond, force_set);
}

/* Set TS Route Info */
void frontend_set_ts_route(struct nim_device *nim, struct ft_ts_route *route)
{
    	struct dmx_device *dmx = NULL;

    	if((route == NULL) || (route->ts_route_enable == 0))
    	{
        	return;
    	}

	//Set TS Input Source Attribute
    	//tsi_mode_set(route->tsiid, route->tsi_mode); // move to system_hw_init
	//Select TS Input Source for Output TS of TSI
    	tsi_select(route->ts_id, route->tsiid);
	//Select TSI Output TS for DMX
    	tsi_dmx_src_select(route->dmx_id, route->ts_id);
    	//Set TS Pass CI CAM or Bypass
    	if(route->ci_enable)
    	{
        	dmx = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, route->dmx_id);
        	//If needed, Set NIM TS Mode and Reset DMX
        	if((nim != NULL) && (dmx != NULL))
        	{

        	}
    	}
}

/* Check whether NIM Param is changed or not */
BOOL frontend_check_nim_param(struct nim_device *nim, union ft_xpond* xpond, struct ft_antenna *antenna)
{
	BOOL ret = FALSE;
	INT32 freq = 0;
	UINT8 fec = 0;
	UINT32 sym = 0;
	UINT32 tmp;

	if(nim == NULL || xpond == NULL ||antenna == NULL)
	{
		return ret;
	}

	if(xpond->common.type == FRONTEND_TYPE_S)
	{
		UINT8 pol;
		INT32 tuning_frq = 0;

		//Calculate Tuning Frequency according to Antenna Info
        	switch(antenna->lnb_type)
        	{
            	case LNB_CTRL_22K:                
                	if(xpond->s_info.frq > KU_LNB_22K_EDGE_FREQUENCY)
                	{
                    		tuning_frq = xpond->s_info.frq - ((antenna->lnb_high > antenna->lnb_low) ? antenna->lnb_high : antenna->lnb_low);
                	}
                	else
                	{
                    		tuning_frq = xpond->s_info.frq - ((antenna->lnb_high > antenna->lnb_low) ? antenna->lnb_low : antenna->lnb_high);
                	}
              	break;
            	case LNB_CTRL_POL:
                	pol = ((antenna->pol == 0) || (antenna->pol == 3)) ? (xpond->s_info.pol + 1) : (antenna->pol);
                	if(pol == 1)
                	{
                    		tuning_frq = antenna->lnb_low - xpond->s_info.frq;
                	}
                	else
                	{
                    		tuning_frq = antenna->lnb_high - xpond->s_info.frq;
                	}
                	break;
                case LNB_CTRL_UNICABLE:
                    tuning_frq = antenna->unicable_freq;
                    break;
            	case LNB_CTRL_STD:
            	default:
                    	tuning_frq = (((antenna->lnb_low != 0) ? antenna->lnb_low : antenna->lnb_high)) - xpond->s_info.frq;
                	break;
        	}
			
        	if(tuning_frq < 0)
        	{
            		tuning_frq = -tuning_frq;
        	}

		//Get NIM Freq
		//param "1" mean that cur freq is that user latest setting, not realy work freq
		freq = nim_io_control(nim, NIM_DRIVER_GET_CUR_FREQ, 1);
					
		//Check Freq Freq Offset within 2MHz, Same TP
		//NOTE: unsigned subtract
		if (freq >= tuning_frq)
			tmp = freq - tuning_frq;
		else
			tmp = tuning_frq - freq;
		
		if(tmp > 2)
		{
			ret = TRUE;
		}
		//Check Sym Rate
		else 
		{
            if(NULL == nim->do_ioctl)
                return ret;            
            nim->do_ioctl(nim, NIM_DRIVER_GET_SYM, (UINT32)&sym);          
			//Sym Rate Offset within 150, Same TP
			//NOTE: unsigned subtract
			if (sym >= xpond->s_info.sym)
				tmp = sym - xpond->s_info.sym;
			else
				tmp = xpond->s_info.sym - sym;
			
			if(tmp > 150)
			{
				ret = TRUE;
			}
		}
	}
	else if(xpond->common.type == FRONTEND_TYPE_C)
	{
		//Get NIM Freq		
		if(SUCCESS != nim_get_freq(nim, &freq))
		{
			return ret;
		}
		
		//Freq Offset within 1MHz, Same TP
		if((UINT32)freq >= xpond->c_info.frq)
			tmp = freq - xpond->c_info.frq;
		else
			tmp = xpond->c_info.frq - freq;
		if(tmp > 100)
		{
			ret = TRUE;
		}
		//Check modulation
		else 
		{
			if(SUCCESS != nim_get_FEC(nim, &fec))
			{
				return ret;
			}
			if(fec != xpond->c_info.modulation)
			{
				ret = TRUE;
			}
		}
	}
	else if(xpond->common.type == FRONTEND_TYPE_T)
	{
		if(SUCCESS != nim_get_freq(nim, &freq))
		{
			return ret;
		}
		
		if((UINT32)freq >= xpond->t_info.frq)
			tmp = freq - xpond->t_info.frq;
		else
			tmp = xpond->t_info.frq - freq;

		if(tmp>100)
			ret = TRUE;
		else
			ret = FALSE;
	}
	
	return ret;
}

/* Get Status of NIM or DMX Device in TS Route */
void _ts_route_get_dev_state(UINT32 hld_type, void *dev, UINT32 *status)
{
	UINT16 i;
	UINT8 dev_id;
	
	switch(hld_type)
	{
	//Get NIM Device Status
	case HLD_DEV_TYPE_NIM:
		dev_id = (((struct nim_device *)dev)->type) & HLD_DEV_ID_MASK;
		*status = DEV_FRONTEND_STATUS_PLAY;
		for(i=0; i<CC_MAX_TS_ROUTE_NUM; i++)
		{
			if((g_ts_route_info[i].enable == 1) && (g_ts_route_info[i].nim_id == dev_id))
			{
				if(g_ts_route_info[i].state & TS_ROUTE_STATUS_RECORD)
				{
					*status = DEV_FRONTEND_STATUS_RECORD;
					break;
				}
			}
		}
		break;
	//Get DMX Device Status
	case HLD_DEV_TYPE_DMX:
		dev_id = (((struct dmx_device *)dev)->type) & HLD_DEV_ID_MASK;
		*status = DEV_DMX_STATUS_PLAY;
		for(i=0; i<CC_MAX_TS_ROUTE_NUM; i++)
		{
			if((g_ts_route_info[i].enable == 1) && (g_ts_route_info[i].dmx_id == dev_id))
			{
				if(g_ts_route_info[i].state & TS_ROUTE_STATUS_RECORD)
				{
					*status = DEV_DMX_STATUS_RECORD;
					break;
				}
			}
		}
		break;
	default:
		break;
	}

	return;
}

/* Get DMX Config Info in TS Route */
void _ts_route_get_dmx_config(struct dmx_device *dmx, struct dmx_config *config)
{
	UINT16 i, j = 0;
	UINT8 dev_id;
	
	MEMSET(config, 0, sizeof(struct dmx_config));
	dev_id = (dmx->type) & HLD_DEV_ID_MASK;

	for(i=0; i<CC_MAX_TS_ROUTE_NUM; i++)
	{
		if((g_ts_route_info[i].enable == 1) && (g_ts_route_info[i].dmx_id == dev_id))
		{
			config->tp_id = g_ts_route_info[i].tp_id;
			if(g_ts_route_info[i].sim_num)
			{
				MEMCPY(&config->dmx_sim_info[j], &g_ts_route_info[i].dmx_sim_info[0], g_ts_route_info[i].sim_num * sizeof(struct dmx_sim));
				j += g_ts_route_info[i].sim_num;
			}
		}
	}
	
	return;
}

/* Create TS Route */
UINT32 ts_route_create(struct ts_route_info *ts_route)
{
	UINT32 ret = 0;

	//Get TS Route Number for Check whether TS Route is Valid or not 
	ret = __ts_route_get_valid();
	if(ret >= CC_MAX_TS_ROUTE_NUM)
	{
		return ret;
	}

	//Copy TS Route Info
	MEMSET(&g_ts_route_info[ret], 0, sizeof(struct ts_route_info));
	MEMCPY(&g_ts_route_info[ret], ts_route, sizeof(struct ts_route_info));
	g_ts_route_info[ret].enable = 1;
	g_ts_route_info[ret].id = ret;
	g_ts_route_info[ret].flag_lock = 1;
	g_ts_route_info[ret].flag_scramble = 0;

	return ret;
}

/* Delete TS Route */
RET_CODE ts_route_delete(UINT32 id)
{
	RET_CODE ret = RET_SUCCESS;

	if(g_ts_route_info[id].enable == 0)
	{
		ret = RET_FAILURE;
	}
	else
	{
		MEMSET(&g_ts_route_info[id], 0, sizeof(struct ts_route_info));
	}
	
	return ret;
}

/* Get TS Route Info according to TS Route ID */
UINT8 ts_route_get_num(void)
{
	UINT8 ret = 0;
	UINT16 i;

	for(i=0; i<CC_MAX_TS_ROUTE_NUM; i++)
	{
		if(g_ts_route_info[i].enable == 1)
		{
			ret++;
		}
	}
	
	return ret;
}

/* Get TS Route Info according to TS Route ID */
RET_CODE ts_route_get_by_id(UINT32 id, struct ts_route_info *ts_route)
{
	RET_CODE ret = RET_SUCCESS;

	if(g_ts_route_info[id].enable == 0)
	{
		ret = RET_FAILURE;
	}
	else
	{
		MEMCPY(ts_route, &g_ts_route_info[id], sizeof(struct ts_route_info));
		__ts_route_check_flag(ts_route);
	}
	
	return ret;
}

/* Get TS Route ID and Info according to TS Route Type */
RET_CODE ts_route_get_by_type(UINT32 type, UINT32 *ts_route_id, struct ts_route_info *ts_route)
{
	RET_CODE ret = RET_FAILURE;
	UINT16 i;

	if((ts_route_id != NULL) || (ts_route != NULL))
	{
		for(i=0; i<CC_MAX_TS_ROUTE_NUM; i++)
		{
			if((g_ts_route_info[i].enable == 1) && (g_ts_route_info[i].type == type))
			{
				if(ts_route_id != NULL)
				{
					*ts_route_id = i;
				}
				if(ts_route!= NULL)
				{
					MEMCPY(ts_route, &g_ts_route_info[i], sizeof(struct ts_route_info));
					__ts_route_check_flag(ts_route);
				}
				ret = RET_SUCCESS;
				break;
			}
		}
	}

	return ret;
}

/* Get TS Route ID and Info of Prog which is Recording according to Prog ID */
RET_CODE ts_route_get_record(UINT32 prog_id, UINT32 *ts_route_id, struct ts_route_info *ts_route)
{
	RET_CODE ret = RET_FAILURE;
	UINT16 i;

	if((ts_route_id != NULL) || (ts_route != NULL))
	{
		for(i=0; i<CC_MAX_TS_ROUTE_NUM; i++)
		{
			if((g_ts_route_info[i].enable == 1) && (g_ts_route_info[i].is_recording == 1) && (g_ts_route_info[i].prog_id == prog_id))
			{
				if(ts_route_id != NULL)
				{
					*ts_route_id = i;
				}
				if(ts_route!= NULL)
				{
					MEMCPY(ts_route, &g_ts_route_info[i], sizeof(struct ts_route_info));
					__ts_route_check_flag(ts_route);
				}
				ret = RET_SUCCESS;
				break;
			}
		}
	}

	return ret;
}

/* Update TS Route */
RET_CODE ts_route_update(UINT32 id, struct ts_route_info *ts_route)
{
	RET_CODE ret = RET_SUCCESS;

	if(g_ts_route_info[id].enable == 0)
	{
		ret = RET_FAILURE;
	}
	else
	{
		MEMCPY(&g_ts_route_info[id], ts_route, sizeof(struct ts_route_info));
	}
	
	return ret;
}

/* Get TS Route ID of TS Route which Use Right CI Slot */
INT16 ts_route_check_ci(UINT8 ci_id)
{
	INT16 ret = -1;
	UINT16 i;

	for(i=0; i<CC_MAX_TS_ROUTE_NUM; i++)
	{
		if(g_ts_route_info[i].enable == 1)
		{
			if(((g_ts_route_info[i].ci_mode == CI_SERIAL_MODE) && ((g_ts_route_info[i].cia_used) || (g_ts_route_info[i].cib_used)))
				|| ((g_ts_route_info[i].ci_mode == CI_PARALLEL_MODE) && ((ci_id == 0) ? g_ts_route_info[i].cia_used : ((ci_id==1) ? g_ts_route_info[i].cib_used : 0))))
			{
				ret = i;
				break;
			}
		}
	}

	return ret;
}

/* Get ID and Number of All TS Routes which Include Right CI Slot and Get ID of TS Route which Use Right CI Slot Currently */
INT16 ts_route_check_ci_route(UINT8 ci_id, UINT8 *route_num, UINT16 *routes)
{
	INT16 ret = -1;
	UINT16 i;

	*route_num = 0;
	for(i=0; i<CC_MAX_TS_ROUTE_NUM; i++)
	{
		if(g_ts_route_info[i].enable == 1)
		{
			if(((g_ts_route_info[i].ci_mode == CI_SERIAL_MODE) && ((g_ts_route_info[i].cia_included) || (g_ts_route_info[i].cib_included)))
				|| ((g_ts_route_info[i].ci_mode == CI_PARALLEL_MODE) && ((ci_id==0) ? g_ts_route_info[i].cia_included : ((ci_id==1) ? g_ts_route_info[i].cib_included : 0))))
			{
				routes[*route_num] = i;
				(*route_num)++;
				if(((g_ts_route_info[i].ci_mode == CI_SERIAL_MODE) && ((g_ts_route_info[i].cia_used) || (g_ts_route_info[i].cib_used)))
					|| ((g_ts_route_info[i].ci_mode == CI_PARALLEL_MODE) && ((ci_id==0) ? g_ts_route_info[i].cia_used : ((ci_id==1) ? g_ts_route_info[i].cib_used : 0))))
				{
					ret = i;
				}
			}			
		}
	}

	return ret;
}

/* Get TS ID of Matched TS Route according to Input DMX ID */
UINT8 ts_route_check_TS_by_dmx(UINT8 dmx_id)
{
	UINT8 ret = 0;
	UINT16 i;

	for(i=0; i<CC_MAX_TS_ROUTE_NUM; i++)
	{
		if(g_ts_route_info[i].enable == 1)
		{
			if(g_ts_route_info[i].dmx_id == dmx_id)
			{
				ret = g_ts_route_info[i].ts_id;
				break;
			}			
		}
	}

	return ret;
}

/* Get ID and Number of Matched TS Route according to Input DMX ID */
void ts_route_check_dmx_route(UINT8 dmx_id, UINT8 *route_num, UINT16 *routes)
{
	UINT16 i;

	*route_num = 0;
	for(i=0; i<CC_MAX_TS_ROUTE_NUM; i++)
	{
		if(g_ts_route_info[i].enable == 1)
		{
			if(g_ts_route_info[i].dmx_id == dmx_id)
			{
				routes[*route_num] = i;
				(*route_num)++;
			}			
		}
	}
}

/* Get ID and Number of Matched TS Route according to Input TP ID */
void ts_route_check_tp_route(UINT32 tp_id, UINT8 *route_num, UINT16 (*routes)[])
{
	UINT16 i;

	*route_num = 0;
	for(i=0; i<CC_MAX_TS_ROUTE_NUM; i++)
	{
		if(g_ts_route_info[i].enable == 1)
		{
			if(g_ts_route_info[i].tp_id == tp_id)
			{
				(*routes)[*route_num] = i;
				(*route_num)++;
			}			
		}
	}
}

void ts_route_check_nim_route(UINT32 nim_id, UINT8 *route_num, UINT16 *routes)
{
	UINT16 i;

	*route_num = 0;
	for(i=0; i<CC_MAX_TS_ROUTE_NUM; i++)
	{
		if(g_ts_route_info[i].enable == 1)
		{
			if(g_ts_route_info[i].nim_id == nim_id)
			{
				routes[*route_num] = i;
				(*route_num)++;
			}			
		}
	}
}

UINT32 ts_route_get_by_prog_id(UINT32 prog_id, UINT8 dmx_id,  UINT8 is_pip, struct ts_route_info *ts_route)
{
	RET_CODE ret = RET_SUCCESS;
	UINT8 i;

	for(i=0; i<CC_MAX_TS_ROUTE_NUM; i++)
	{
		if((g_ts_route_info[i].enable == 1))
		{
			if((g_ts_route_info[i].type == TS_ROUTE_PIP_PLAY) && (is_pip) && (g_ts_route_info[i].prog_id == prog_id))
				break;
			if((g_ts_route_info[i].type != TS_ROUTE_PIP_PLAY) && (!is_pip) && (g_ts_route_info[i].prog_id == prog_id) && (g_ts_route_info[i].dmx_id == dmx_id))
				break;
		}	
	}

	if(i >= CC_MAX_TS_ROUTE_NUM)
	{
		ret = RET_FAILURE;
	}
	else
	{
		MEMCPY(ts_route, &g_ts_route_info[i], sizeof(struct ts_route_info));
	}
	return ret;
}
UINT8 ts_route_set_ci_info(UINT32 sim_id,CA_INFO *ca_info,UINT8 ca_count)
{
	UINT8	i;
	for (i=0;i<5;i++)
	{
		if((g_ts_route_info[i].enable)&&(g_ts_route_info[i].dmx_sim_info[0].sim_id == sim_id))
		{
			MEMCPY(g_ts_route_info[i].ca_info,ca_info,ca_count*sizeof(CA_INFO));
			g_ts_route_info[i].ca_count = ca_count;
			g_ts_route_info[i].ca_info_enable= 1;
			return RET_SUCCESS;
		}
	}
	return RET_FAILURE;
}

UINT8 is_ca_info_in_ts_route(UINT32 sim_id)
{
	UINT8 i;
	for (i=0;i<5;i++)
	{
		if((g_ts_route_info[i].dmx_sim_info[0].sim_id == sim_id)&&(g_ts_route_info[i].ca_info_enable == 1))
			return RET_SUCCESS;
	}
	return RET_FAILURE;
}

UINT8 ts_route_get_by_sim_id(UINT32 sim_id,UINT8 is_pip,	struct ts_route_info* ts_route)
{
	UINT8 i,j;
	if (ts_route ==NULL)
		return RET_FAILURE;
	for(i=0;i<5;i++)
	{
		if (!g_ts_route_info[i].enable)
			continue;
		for(j=0;j<DEV_DMX_SIM_CNT>>1;j++)
		{
			if ((g_ts_route_info[i].dmx_sim_info[j].sim_id ==sim_id)&&(g_ts_route_info[i].type ==  TS_ROUTE_PIP_PLAY)&&(is_pip == 1))
			{
				MEMCPY(ts_route,&g_ts_route_info[i],sizeof(struct ts_route_info));
				return RET_SUCCESS;
			}
			if((g_ts_route_info[i].dmx_sim_info[j].sim_id ==sim_id)
				&&((g_ts_route_info[i].type ==  TS_ROUTE_MAIN_PLAY) ||(g_ts_route_info[i].type ==  TS_ROUTE_BACKGROUND))
				&&(is_pip == 0))
			{
				MEMCPY(ts_route,&g_ts_route_info[i],sizeof(struct ts_route_info));
				return RET_SUCCESS;
			}
		}
	}
	MEMSET(ts_route,0,sizeof(struct ts_route_info));
	return RET_FAILURE;		
}
#ifdef COMBO_CA_PVR
UINT8 ts_route_check_recording_by_nim_id(UINT32 nim_id)
{
	UINT8 route,slot;
	struct ts_route_info ts_route;
	for(route=0;route<CC_MAX_TS_ROUTE_NUM;route++)
	{
		MEMSET(&ts_route,0,sizeof(struct ts_route_info));
		if(ts_route_get_by_id(route,&ts_route) == RET_FAILURE)
			continue;
		if(!ts_route.enable) 
			continue;
		if(ts_route.nim_id == nim_id && ts_route.is_recording == TRUE && (ts_route.state & TS_ROUTE_STATUS_RECORD))
		{
			//libc_printf("ts_route_check_recording_by_nim_id => RET_SUCCESS\n");
			return RET_SUCCESS;
		}
	}
	//libc_printf("ts_route_check_recording_by_nim_id => RET_FAILURE\n");
	return RET_FAILURE;
}
#endif
/*
UINT8  ts_route_delete_ca_slot_info()
{
	UINT8 	i;
	UINT8 	scramble_type = 0;
	RET_CODE	ret = RET_FAILURE,dmx_state;

	for(i=0;i<5;i++)
	{

		if(!g_ts_route_info[i].enable) continue;
		
		//if((ts_route.type == TS_ROUTE_PIP_PLAY)&&(RET_SUCCESS == dmx_io_control(((ts_route.dmx_id == 0) ? g_dmx_dev : g_dmx_dev2), IS_BOTH_SLOT_PLAY,0)))
		//	dmx_state = dmx_io_control(((ts_route.dmx_id == 0) ? g_dmx_dev : g_dmx_dev2), IS_AV_SCRAMBLED_EXT,(&scramble_type));
		//else
		
			dmx_state = dmx_io_control(((g_ts_route_info[i].dmx_id == 0) ? g_dmx_dev : g_dmx_dev2), IS_AV_SCRAMBLED,(UINT32)&scramble_type);
		if ((g_ts_route_info[i].dmx_id < 2)
			&&(dmx_state == RET_SUCCESS )
			&&((((scramble_type & (VDE_TS_SCRBL|VDE_PES_SCRBL|AUD_TS_SCRBL|AUD_PES_SCRBL|VDE_STR_INVALID)) != 0x00)&&(g_ts_route_info[i].type==TS_ROUTE_PIP_PLAY))
				||(((scramble_type & (VDE_TS_SCRBL|VDE_PES_SCRBL|AUD_TS_SCRBL|AUD_PES_SCRBL|VDE_STR_INVALID|AUD_STR_INVALID)) != 0x00)
					&&((g_ts_route_info[i].type==TS_ROUTE_MAIN_PLAY)||(g_ts_route_info[i].type==TS_ROUTE_PLAYBACK)))))
		{
			if(g_ts_route_info[i].cia_used)
			{
				g_ts_route_info[i].ca_slot_ready[0] = 0;
			}
			else if(g_ts_route_info[i].cib_used)
			{
				g_ts_route_info[i].ca_slot_ready[1] = 0;
			}
			ret = RET_SUCCESS;
		}		
	}
	return ret;
}
*/

INT8 ts_route_get_nim_tsiid(UINT8 nim_id)
{
	return nim_tsiid[nim_id];
}

void ts_route_set_nim_tsiid(UINT8 nim_id, INT8 tsiid)
{
	nim_tsiid[nim_id] = tsiid;
}

void chchg_set_local_position(double longtitude,double latitude)
{
	ENTER_FRONTEND_API();
	local_longtitude = longtitude;
	local_latitude = latitude;
	LEAVE_FRONTEND_API();
}

void chchg_get_local_position(double *longtitude,double *latitude)
{
	ENTER_FRONTEND_API();
	*longtitude = local_longtitude;
	*latitude = local_latitude;
	LEAVE_FRONTEND_API();
}

